<?php

/* ========================================================================= */
/* This file is part of the HypnoPHP Framework Library                       */
/* Copyright (c) 2009-2010, Radu Buzea                                       */
/* ========================================================================= */

/**
* @author Radu Buzea
* @copyright Copyright (c) 2009-2010, Radu Buzea (www.hypnosis.ro)
* @license GNU Lesser General Public License (www.gnu.org/copyleft/lesser.html)
* @package HypnoPHP
* @category Core
* @version 1.0.3
*/

defined('HYPNOPHP_APPLICATION') or
die("Cannot use <i>" . basename(__FILE__) . "</i> outside HypnoPHP Application");

// ============================================================================
// Class: BaseView
// ============================================================================

class HBaseView extends HBaseObject {

	protected $__render_params = array();
	protected $__page_vars = array();
	protected $__parent_controller = null;
	protected $__helpers = array();

	# ###########################################################################

	/**
	* initialize object properties
	*
	* @return void
	*/
	public function __initialize()
	{
		$this->disable_layout = false;
		$this->__render_params = array();
		$this->__page_vars = array();
		$this->__parent_controller = null;
		$this->__helpers = array();
		if (func_num_args() > 0) {
			$args = func_get_arg(0);
			if (is_array($args) && isset($args[0]) && is_object($args[0])) {
				$this->__parent_controller = $args[0];
			}
		}
	}

	# ###########################################################################

	/**
	* Get the view template file associated to the parent controller's action
	*
	* @param string $action_name The controller action name
	* @return string The file name
	*/
	public function getTemplateFile($action_name = '')
	{
		global $_HAPPLICATION_PATHS, $_HAPPLICATION_ROOT_PATH;
		$controller_name = '';
		if (is_object($this->__parent_controller)) {
			$controller_name = get_class($this->__parent_controller);
		}
		$view_path = sprintf($_HAPPLICATION_PATHS['app_views'], $_HAPPLICATION_ROOT_PATH) . DS;
		$controller_path =  str_replace(array('Controller_', '_'), array('', DS), $controller_name);
		$view_file = "{$view_path}{$controller_path}.{$action_name}." . HGLOBAL_TEMPLATE_EXT;
		if (!is_file($view_file)) {
			$view_file = "{$view_path}{$controller_path}" . DS . "{$action_name}" . HGLOBAL_TEMPLATE_EXT;
		}
		if (is_file($view_file)) { return $view_file; }
		else { return ''; }
	}

	# ###########################################################################

	/**
	* Get a list of template render variables
	*
	* @return void
	*/
	public function getRenderParams()
	{
		return $this->__render_params;
	}

	# ###########################################################################

	/**
	* Set the list of template render variables
	*
	* @param array $render_params
	* @return void
	*/
	public function setRenderParams($render_params = array())
	{
		$this->__render_params = $render_params;
	}

	# ###########################################################################

	/**
	* Get or set the parent controller object
	*
	* @param object $controller (HBaseController)
	* @return object (HBaseController) or bool (on set)
	*/
	public function parentController($controller = null)
	{
		if (!is_null($controller)) {
			if (is_object($controller)) {
				$this->__parent_controller = $controller;
				return true;
			}
			return false;
		}
		return $this->__parent_controller;
	}

	# ###########################################################################

	/**
	* Set one or more variables to be used in the template
	*
	* @param string or array $name
	* @param mixed $value
	* @return void
	*/
	public function setVar($param1, $param2 = null)
	{
		$vars = null;
		if (is_array($param1)) {
			if (is_array($param2)) { $vars = array_combine($param1, $param2); }
			else { $vars = $param1; }
		} else {
			$vars = array($param1 => $param2);
		}
		if (is_null($vars) || count($vars) == 0) { return false; }
		foreach ($vars as $var_name => $var_value) {
			if (!$this->__checkVarName($var_name, true)) { return false; }
			$this->__page_vars[$var_name] = $var_value;
		}
		return true;
	}

	# ###########################################################################

	/**
	* Alias for 'setVar' method
	*
	* @param string or array $name
	* @param mixed $value
	* @return void
	*/
	public function set($param1, $param2 = null)
	{
		return $this->setVar($param1, $param2);
	}

	# ###########################################################################

	/**
	* Get a variable form the list of variables to be used in the template
	*
	* @param string $param The variable name
	* @return mixed
	*/
	public function getVar($param = '')
	{
		if (!isset($this->__page_vars[$param])) { return null; }
		else { return $this->__page_vars[$param]; }
	}

	# ###########################################################################

	/**
	* Alias for 'getVar' method
	*
	* @param string $param The variable name
	* @return mixed
	*/
	public function get($param = '')
	{
		return $this->getVar($param);
	}

	# ###########################################################################

	/**
	* Get the list of variables to be used in the template
	*
	* @return array
	*/
	public function getAll()
	{
		return $this->__page_vars;
	}

	# ###########################################################################

	/**
	* Search for a script file and include it in the template
	*
	* @param string $filename
	* @return void
	*/
	public function useFile($filename = '')
	{
		$filename = trim($filename);
		if (DS != '/' && strpos($filename, '/') !== false) {
			$filename = str_replace('/', DS, $filename);
		}
		$file_loaded = false;
		if (is_file($filename)) {
			include_once $path . DS . $filename;
			$file_loaded = true;
		} else {
			global $_HAPPLICATION_PATHS, $_HAPPLICATION_ROOT_PATH;
			$paths = array(
				$_HAPPLICATION_PATHS['system_lib'],
				$_HAPPLICATION_PATHS['system_helpers'],
			);
			$app_paths = array('app_controllers', 'app_helpers', 'app_models');
			foreach ($app_paths as $app_path) {
				$paths[] = sprintf($_HAPPLICATION_PATHS[$app_path], $_HAPPLICATION_ROOT_PATH);
			}
			foreach ($paths as $path) {
				if (is_file($path . DS . $filename)) {
					include_once $path . DS . $filename;
					$file_loaded = true;
					break;
				}
			}
		}
		if (!$file_loaded) {
			$this->addError("Unable to load file <i>{$filename}</i>", E_USER_WARNING);
		}
	}

	# ###########################################################################

	/**
	* Search and loads a helper file in the template
	*
	* @param string $filename
	* @return void
	*/
	public function loadHelper($helper_name = '')
	{
		$helper_name = trim($helper_name);
		if ($helper_name == '') { return null; }
		if (isset($this->__helpers[$helper_name])) { return $this->__helpers[$helper_name]; }
		if (!class_exists($helper_name, true)) { return null; }
		$this->__helpers[$helper_name] = new $helper_name($this->__parent_controller, $this);
		return $this->__helpers[$helper_name];
	}

	# ###########################################################################

	/**
	* Call methods inside the hellper as they are members of the viewer object
	*
	* @param string $func_name The function name
	* @param array $func_args The function arguments
	* @return void
	*/
	public function __call($func_name = '', $func_args = array())
	{
		if (count($this->__helpers) > 0) {
			$func_name = trim($func_name);
			foreach ($this->__helpers as $helper) {
				if (method_exists($helper, $func_name)) {
					return call_user_func_array(array($helper, $func_name), $func_args);
				}
			}
		}
		$class_name = __CLASS__;
		$this->addError("Call to undefined method <i>{$class_name}::{$method_name}</i>", E_USER_ERROR);
	}

	# ###########################################################################

	/**
	* Render a block content from another controller inside the current template
	*
	* @param string $controller_name The controller name or NULL if the parent controller will be used
	* @param string $action_name The action name
	* @param array $action_params A list of action params
	* @param bool $new_ctrl_instance Use the HApplication::runController( to get the block content
	* @return string
	*/
	public function blockContent($controller_name = null, $action_name = '',
		$action_params = array(), $new_ctrl_instance = false)
	{
		if (empty($controller_name) || !is_string($controller_name)) {
			$controller = $this->parentController();
			if (!is_object($controller)) {
				$this->addError("Undefined block controller", E_USER_WARNING);
				return null;
			}
		}
		if (empty($action_name) || !is_string($action_name)) {
			$this->addError("Undefined block controller action", E_USER_WARNING);
			return null;
		}
		if (isset($controller) && !$new_ctrl_instance) {
			return $controller->executeAction($action_name, $action_params);
		} else {
			return HApplication::runController($controller_name, $action_name, $action_params);
		}
	}

	# ###########################################################################

	/**
	* Render and prints a block content from another controller inside the current template
	*
	* @param mixed $controller_name
	* @param mixed $action_name
	* @param mixed $action_params
	* @param mixed $new_ctrl_instance
	* @return void
	*/
	public function block($controller_name = null, $action_name = null,
		$action_params = array(), $new_ctrl_instance = false)
	{
		$block_content = $this->blockContent($controller_name, $action_name, $action_params, $new_ctrl_instance);
		print $block_content;
	}

	# ###########################################################################

	/**
	* Render the template
	*
	* @param string $action_name The action name
	* @param string $action_result The action result (from the controller)
	* @return string
	*/
	public function render($action_name = '', $action_result = '')
	{
		if (is_array($this->__render_params)) {
			foreach ($this->__render_params as $render_key => $render_value) {
				$render_key = strtolower($render_key);
				switch ($render_key) {
					case 'header':
						if (is_array($render_value)) { HResponse::set_header($render_value); }
						break;
					case 'helpers':
						if (is_array($render_value)) {
							foreach ($render_value as $helper_name) {
								$this->loadHelper($helper_name);
							}
						}
						break;
					default:
						$this->setVar($render_key, $render_value);
				}
			}
		}

		if (is_object($this->__parent_controller)) {
			$controller_name = get_class($this->__parent_controller);
			if (isset($this->__parent_controller->disable_layout)) {
				$this->disable_layout = boolval($this->__parent_controller->disable_layout);
			}
		} else {
			$controller_name = '';
		}

		if ($controller_name != '') {
			$key_facts = str_replace('Controller_', '', $controller_name) . '_' . $action_name;
		} else {
			$key_facts = "controller_{$action_name}";
		}
		$key_tpl_file = "{$key_facts}_template_file";
		$this->__page_vars[$key_tpl_file] = $this->getTemplateFile($action_name);
		if ($action_result != '') {
			$key_action_result = "{$key_facts}_action_result";
			$this->__page_vars[$key_action_result] = $action_result;
		}
		extract($this->__page_vars, EXTR_SKIP);
		ob_start();
		HApplication::incObCount();
		if ($this->__page_vars[$key_tpl_file] != '') {
			include $this->__page_vars[$key_tpl_file];
		} else {
			echo $action_result;
		}
		$render_content = ob_get_clean();
		HApplication::decObCount();
		if (!$this->disable_layout && HApplication::getObCount() == 0) {
			if (isset($this->__helpers['Header'])) {
				$header_code = $this->__helpers['Header']->output();
				if ($header_code != '') {
					$render_content = $header_code . PHP_EOL . $render_content;
				}
			}
		}
		return $render_content;
	}

	# ###########################################################################

}
